unit Agent;

interface
uses
  QTable, Grid, Graphics, Path;

type

  TQLearningMode = (qmExploring, qmExploiting);
  
  TAgent = class
  private
    FQTable : TQTable;
    FGrid   : TGrid;

    FInitialState,
    FState  : TState;
    
    FImage  : TBitmap;

    //FMode   : TQLearningMode;
    FExploitingRate : Double;
    procedure SetState(const Value: TState);
  public

    constructor Create (Grid : TGrid; QTable : TQTable;   ExploitingRate : Double);

    function MoveToState (State : TState) : Boolean;
    function Move : TAction;
    function Feel : TGridItem;

    procedure QPath(var Path : TPath);

    property Image : TBitmap read FImage;
    property InitialState : TState read FInitialState write FInitialState;
    property State : TState read FState write SetState;
    property QTable : TQTable read FQTable write FQTable;
    property Grid : TGrid read FGrid;
    property ExploitingRate : Double read FExploitingRate write FExploitingRate;
  end;

implementation

{ TAgent }

constructor TAgent.Create(Grid: TGrid; QTable: TQTable;
  ExploitingRate : Double);
begin
  FGrid := Grid;
  FQTable := QTable;

  //FMode := Mode;
  FExploitingRate := ExploitingRate;
  
  FImage := TBitmap.Create;
  FImage.TransparentColor := clFuchsia;
  FImage.Transparent := True;
  FImage.LoadFromFile('Images\green.bmp');
end;

function TAgent.Feel: TGridItem;
begin
  Result := FGrid.Items[FState.Row, FState.Col];
end;

function TAgent.Move: TAction;
var
  Action : TAction;

  NewState : TState;

  Mode : TQLearningMode;
begin
  NewState := FState;
  Action := acUp;

  if Random <= FExploitingRate then
    Mode := qmExploiting
  else
    Mode := qmExploring;
  
  case Mode of
    qmExploring :
      begin
        Action := TAction (Random (Integer (High (TAction))+1)); //rand
        NewState := FGrid.ChangeState (FState, Action);

        while (NewState = FState) or (NewState.StateType = stWall) do
          begin
            Action := TAction (Random (Integer (High (TAction))+1)); //rand
            NewState := FGrid.ChangeState (FState, Action);
          end;

      end;

    qmExploiting :
      begin
        Action :=  FQTable.BestAction(FState);
        NewState := FGrid.ChangeState (FState, Action);
      end;
  end;
  Result := Action;
  State := NewState;

end;

function TAgent.MoveToState(State: TState): Boolean;
begin
  Result := True;

  Self.State := State;

end;

procedure TAgent.QPath (var Path : TPath);
var
  //Mode : TQLearningMode;
  ExploitingRate : Double;
  OldState : TState;
begin
  //Mode := FMode;
  ExploitingRate := FExploitingRate;
  //FMode := qmExploiting;
  FExploitingRate := 1;
  
  Path.Add(FState);
  OldState := FState;
  Move;
  Path.Add(FState);
  while (OldState <> FState)
    and (FState.StateType <> stHole)
    and (FState.StateType <> stMonster)
    and (FState.StateType <> stGold) do
    begin
      OldState := FState;
      Move;
      Path.Add(FState);
    end;

  //FMode := Mode;
  FExploitingRate := ExploitingRate;

end;

procedure TAgent.SetState(const Value: TState);
begin
  FState := Value;
  FGrid.Items[FState.Row, FState.Col].History.Add(Self);
end;

end.
